#include "tools/bitmap.h"
#include "tools/klib.h"

/**
 * @brief 初始化位图
 *
 * @param bitmap 指向位图的指针
 * @param bits 指向存储位的数组
 * @param count 位的数量
 * @param init_bit 初始位的值
 */
void bitmap_init(bitmap_t *bitmap, uint8_t *bits, int count, int init_bit) {
    bitmap->bit_count = count;
    bitmap->bits = bits;
    kernel_memset(bits, init_bit ? 0xFF : 0x00, (count + 7) / 8);
}

/**
 * @brief 计算存储位图的字节数
 *
 * @param bit_count 位的数量
 * @return int 需要的字节数
 */
int bitmap_byte_count(int bit_count) {
    return (bit_count + 7) / 8;
}

/**
 * @brief 获取位的值
 *
 * @param bitmap 指向位图的指针
 * @param index 要获取的位的索引
 * @return int 位的值（0或1）
 */
int bitmap_get_bit(bitmap_t *bitmap, int index) {
    if (index < 0 || index >= bitmap->bit_count) {
        return -1; // 索引越界
    }
    return (bitmap->bits[(index / 8)] >> (index % 8)) & 1;
}

/**
 * @brief 设置位的值
 *
 * @param bitmap 指向位图的指针
 * @param index 要设置的位的起始索引
 * @param count 要设置的位的数量
 * @param bit 要设置的值（0或1）
 */
void bitmap_set_bit(bitmap_t *bitmap, int index, int count, int bit) {
    for (int i = 0; i < count; i++) {
        int idx = index + i;
        if (bit) {
            bitmap->bits[idx / 8] |= (1 << (idx % 8));
        } else {
            bitmap->bits[idx / 8] &= ~(1 << (idx % 8));
        }
    }
}


/**
 * @brief 检查位是否被设置
 *
 * @param bitmap 指向位图的指针
 * @param index 要检查的位的索引
 * @return int 如果位被设置了，返回1，否则返回0
 */
int bitmap_is_set(bitmap_t *bitmap, int index) {
    return bitmap_get_bit(bitmap, index);
}


/**
 * @brief 在位图中分配连续的位
 *
 * @param bitmap 指向位图的指针
 * @param bit 要检查的位值（0表示空闲，1表示已分配）
 * @param count 要分配的位的数量
 * @return int 分配的位的起始索引，如果没有足够的空间，则返回-1
 */
int bitmap_alloc_nbits(bitmap_t *bitmap, int bit, int count) {
    int free_bits = 0;
    for (int i = 0; i < bitmap->bit_count ; i++) {
        if (bitmap_get_bit(bitmap, i) == bit) {
            free_bits++;
        } else {
            free_bits = 0;
        }
        if (free_bits == count) {
            int start_index = i - count + 1;
            bitmap_set_bit(bitmap, start_index, count, !bit); // 分配位并设置相反的值
            return start_index; // 返回分配位的起始索引
        }
    }
    return -1; // 没有找到足够的空间
}